package com.itcodai.utils.stream.optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;
import java.util.function.Supplier;

/**
 * Optional常见使用方法
 * @author c-fanqj
 * @date 2022/5/20
 * @apiNote
 * 参考 https://mp.weixin.qq.com/s/zS9sdvvYmtWJYkOaN4Nh0Q
 */
public class OptionalExercise {

    private static Logger logger = LoggerFactory.getLogger(OptionalExercise.class);

    public static void main(String[] args) {
        Person person = getPerson();
    }


    public static Person getPerson() {
        // 1、创建一个包装对象值为空的Optional对象
        Optional<String> optEmpty = Optional.empty();
        // 2、创建包装对象值非空的Optional对象
        Optional<String> optOf = Optional.of("optional");
        // 3、创建包装对象值允许为空也可以不为空的Optional对象
        Optional<String> optOfNullable1 = Optional.ofNullable(null);
        Optional<String> optOfNullable2 = Optional.ofNullable("optional");

        Person person = new Person("lele", 5);
        // get()方法是返回一个option的实例值
        System.out.println(Optional.ofNullable(person).get());
        // 姓名：lele，年龄：5

        // isPresent()方法就是会返回一个boolean类型值，如果对象不为空则为真，如果为空则false
        if (Optional.ofNullable(person).isPresent()) {
            System.out.println("不为空");
        } else {
            System.out.println("为空");
        }
        // 不为空

        // ifPresent() 如果对象非空，则运行函数体
        Optional.ofNullable(person)
                .ifPresent(p -> System.out.println("年龄：" + p.getAge()));
        // 年龄：5

        // filter()方法大致意思是，接受一个对象，然后对他进行条件过滤，
        // 如果条件符合则返回Optional对象本身，如果不符合则返回空Optional
        Optional.ofNullable(person)
                .filter(p -> p.getAge() > 2)
                .ifPresent(p -> System.out.println(p));
        // 姓名：lele，年龄：5

        // map()方法将对应Funcation函数式接口中的对象，进行二次运算，
        // 封装成新的对象然后返回在Optional中
        String optName = Optional.ofNullable(person)
                .map(p -> p.getName())
                .orElse("name为空");
        String optName1 = Optional.ofNullable(new Person())
                .map(p -> p.getName())
                .orElse("name为空");
        System.out.println(optName + "---" + optName1); // lele---name为空

        // flatMap() map()方法将对应Optional< Funcation >函数式接口中的对象，进行二次运算，
        // 封装成新的对象然后返回在Optional中
        Optional optional = Optional.ofNullable(person)
                .map(p -> Optional.ofNullable(p.getName())
                        .orElse("name为空"));
        Optional optiona2 = Optional.ofNullable(new Person())
                .map(p -> Optional.ofNullable(p.getName())
                        .orElse("name为空"));
        System.out.println(optional.get() + "---" + optiona2.get()); // lele---name为空

        // orElse()方法(为空返回对象)
        // 如果包装对象为空的话，就执行orElse方法里的value，如果非空，则返回写入对象
        Person person1 = Optional.ofNullable(person)
                .orElse(new Person("小明", 8));
        Person p = null;
        Person person2 = Optional.ofNullable(p)
                .orElse(new Person("小华", 13));
        System.out.println(person1 + "---" + person2);
        // 姓名：lele，年龄：5---姓名：小华，年龄：13

        // orElseGet()方法(为空返回Supplier对象)
        // 这个与orElse很相似，入参不一样，入参为Supplier对象，
        // 为空返回传入对象的.get()方法，如果非空则返回当前对象
        //Supplier<Person> supPerson = Person::new;
        //supPerson.get()
        //Optional<Supplier<Person>> sup = Optional.ofNullable(Person::new));
        Supplier<Person> supPerson = new Supplier<Person>() {
            @Override
            public Person get() {
                return new Person("小杰", 15);
            }
        };
        Optional<Supplier<Person>> sup = Optional.ofNullable(supPerson);
        //调用get()方法，此时才会调用对象的构造方法，即获得到真正对象
        Person person3 = Optional.ofNullable(person).orElseGet(sup.get());
        p = null;
        Person person4 = Optional.ofNullable(p).orElseGet(sup.get());
        System.out.println(person3 + "---" + person4);
        // 姓名：lele，年龄：5---姓名：小杰，年龄：15

        //orElseThrow()方法(为空返回异常)
        //如果为空，就抛出你定义的异常，如果不为空返回当前对象，提升代码的可读性
        Person person5 = Optional.ofNullable(person)
                .orElseThrow(()->new RuntimeException("对象为空"));
        System.out.println(person5);
        /*p = null;
        try {
            Person person6 = Optional.ofNullable(p)
                    .orElseThrow(()->new RuntimeException("对象为空"));
            System.out.println(person6);
        } catch (Exception e) {
            e.printStackTrace();
        }*/

        /*orElse()和orElseGet()和orElseThrow()的异同点
        如果对象不为空，则返回对象，如果为空，则返回方法体中的对应参数，
        所以可以看出这三个方法体中参数是不一样的
        orElse（T 对象）
        orElseGet（Supplier < T >对象）
        orElseThrow（异常）*/

        /*map()和orElseGet的异同点
        方法效果类似，对方法参数进行二次包装，并返回,入参不同
        map（function函数）
        flatmap（Optional< function >函数）*/

        // 实战场景
        // 1.map()和orElseGet的异同点
        Person person7 = new Person("lele", 5);
        Optional.ofNullable(person7)
                .orElseThrow(()->new RuntimeException("对象为空"));

        // 2.逻辑处理
        //
        Optional<Person> perOptional = Optional.ofNullable(person7);
        if(perOptional.isPresent()) {
            Person person6 = perOptional.get();
            System.out.println(person6);
            logger.info(String.valueOf(person6));
        }
        //throw new RuntimeException("不存在");

        return null;
        //return Optional.ofNullable(person).orElse("person为null");
    }


}
